#!/usr/bin/env perl

use warnings;
use strict;

use File::Spec::Functions;

sub find_soruce_files
{
	my @filelist;

	foreach my $dirname (@_) {
		if (-d $dirname) {
			opendir(my $fd, $dirname) or die "Failed to opendir $dirname: $!";

			while (readdir $fd) {
				next if /^\./;

				my $pathname = catfile($dirname, $_);
				push @filelist, &find_soruce_files($pathname);
			}

			closedir $fd;
		} elsif ($dirname =~ /\.(c|h|cpp)$/) {
			push @filelist, $dirname;
		}
	}

	@filelist;
}

my $command = shift @ARGV;
my $single_line = 1;
if ($command eq 'm') {
	$single_line = 0;
} elsif ($command ne 's') {
	die "usage: <s|m> [PATH]\n";
}

my @dirlist = @ARGV;

if (@dirlist <= 0) {
	if (-f "build/core/cavan_main.mk") {
		push @dirlist, ("lib", "include", "app", "cpp", "test", "script", "driver", "android");
	} else {
		push @dirlist, ".";
	}
}

foreach my $pathname (&find_soruce_files(@dirlist)) {
	print "pathname = $pathname\n";

	open(FILE, "<", $pathname) or die "Failed to open file $pathname: $!";
	$_ = join '', <FILE>;

	s/[\t ]+$//mg;
	s/\r\n/\n/mg;

	if ($single_line) {
		s/\}\s*else\s*\{/\} else \{/mg;
		s/\}\s*else\s+(if.*\S)\s*\{/\} else $1 \{/mg;
		s/^(([\t ]+|[\t ]*(class|struct|enum))[^\{\n]+\S)\s*\{[\t ]*$/$1 \{/mg;
		s/^([\t ]*(class|struct|enum))\s*\{[\t ]*$/$1 \{/mg;
		s/^[\t ]*(typedef\s+[^\{\n]+\S)\s*\{[\t ]*$/$1 \{/mg;
		s/=\s*\{[\t ]*$/= \{/mg;
	} else {
		s/^([\t ]*)\}\s*else\s*\{/$1\}\n$1else\n$1\{/mg;
		s/^([\t ]*)\}\s*else\s+(if.*\S)\s*\{/$1\}\n$1else $2\n$1\{/mg;
		s/^(([\t ]*)\S.*\S)[\t ]*\{[\t ]*$/$1\n$2\{/mg;
		# s/^(([\t ]+)case.*:)\s*\{/$1\n$2\t\{/mg;
	}

	s/^[\t ]*((class|struct|enum)[^\{\n]+\([^\{\n]+\))[^\{\n]*\{[\t ]*$/$1\n\{/mg;
	s/^(([\t ]*).*\{)\s*\{/$1\n$2\t\{/mg;
	s/\}\s*else\s*\{[\t ]*\\\s*$/\} else \{ \\/mg;
	s/\}\s*else\s+(if.*\S)\s*\{[\t ]*\\\s*$/\} else $1 \{ \\/mg;
	s/\s*\{[\t ]*\\\s*$/ \{ \\/mg;
	s/do\s*\{/do \{/mg;
	s/\s*\\\s*\{/ \{/mg;

	for my $i (1..10) {
		s/(\([^\*\(\)]+\*?[\t ]*\))([\w\(\&])/$1 $2/mg or last;
	}

	s/(\([^\(\)]+\))[\t ]+Z\b/$1Z/mg;
	s/\(\s*\{/\(\{/mg;

	s/^[\t ]*#if(def\s*__cplusplus|[\t ]+defined[\t ]*\([\t ]*__cplusplus[\t ]*\))\s*extern\s*\"[Cc]\"\s*{\s*#endif/__BEGIN_DECLS/mg;
	s/^[\t ]*#if(def\s*__cplusplus|[\t ]+defined[\t ]*\([\t ]*__cplusplus[\t ]*\))\s*\}\s*#endif/__END_DECLS/mg;
	s/extern[\t ]+\"[Cc]\"[\t ]*\n[\t ]*{/extern "C" \{/mg;

	open(FILE, ">", "$pathname") or die "Failed to open file $pathname: $!";
	print FILE $_;
}
